#include "FLOAT.h"
#include <stdint.h>

// 定义一个联合体 `Float` 来表示浮点数的定点表示
typedef union {
    struct {
        uint32_t m : 23;  // 尾数部分 (23 位)
        uint32_t e : 8;   // 指数部分 (8 位)
        uint32_t s : 1;   // 符号位 (1 位)
    };
    uint32_t val;       // 用于直接访问整体 32 位值
} Float;

// 宏定义：根据符号位决定返回值的正负
#define __sign(x) ((x) & 0x80000000)
// 宏定义：根据符号位将值进行取反处理，适用于取绝对值计算
#define __scale(x) (__sign(x) ? -(x) : (x))

// 定点数乘法实现
FLOAT F_mul_F(FLOAT a, FLOAT b) {
    int64_t scale = ((int64_t)a * (int64_t)b) >> 16; // 将乘法结果右移 16 位以调整定点数位置
    return scale;
}

// 定点数除法实现，使用了内联汇编
FLOAT F_div_F(FLOAT a, FLOAT b) {
    FLOAT q, r;
    // 使用 x86 汇编进行 64 位除法，除数是 32 位
    asm volatile("idiv %2" : "=a"(q), "=d"(r) : "r"(b), "a"(a << 16), "d"(a >> 16));
    return q;
}

// 将浮点数转换为定点数
FLOAT f2F(float a) {
    Float f;
    void *temp = &a;            // 将浮点数 `a` 的地址转换为 `void *`
    f.val = *(uint32_t *)temp;  // 读取浮点数的 32 位二进制表示
    uint32_t m = f.m | (1 << 23); // 将尾数部分左移以包含隐含的 1
    int shift = 134 - (int)f.e;  // 根据指数调整尾数的位置
    // 调整尾数的位移
    if(shift < 0) {
        m <<= (-shift);
    } else {
        m >>= shift;
    }
    return (__sign(f.val) ? -m : m); // 根据符号位决定最终结果的正负
}

// 计算定点数的绝对值
FLOAT Fabs(FLOAT a) {
    return __scale(a); // 使用 __scale 宏来获取绝对值
}

/* Functions below are already implemented */

// 计算定点数的平方根
FLOAT sqrt(FLOAT x) {
    FLOAT dt, t = int2F(2); // 初始猜测值为 2

    do {
        dt = F_div_int((F_div_F(x, t) - t), 2); // 计算改进值
        t += dt; // 更新猜测值
    } while(Fabs(dt) > f2F(1e-4)); // 迭代直到精度满足要求

    return t;
}

// 计算定点数的立方根
FLOAT pow(FLOAT x, FLOAT y) {
    /* 我们只计算 x 的 1/3 次方 */
    FLOAT t2, dt, t = int2F(2); // 初始猜测值为 2

    do {
        t2 = F_mul_F(t, t); // 计算 t 的平方
        dt = (F_div_F(x, t2) - t) / 3; // 计算改进值
        t += dt; // 更新猜测值
    } while(Fabs(dt) > f2F(1e-4)); // 迭代直到精度满足要求

    return t;
}
